﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Xml;
using AutoTaskSchedule.Core.Common;
using AutoTaskSchedule.Core.Extensions;
using AutoTaskSchedule.Core.Models;

namespace AutoTaskSchedule.Core.Business
{
    public class TaskListService : ITaskListService
    {
        private static readonly string TASK_TAG_NAME = "task";

        private static readonly string TASK_OPTION_TAG_NAME = "option";

        private static readonly string TASK_PROPERTY_TAG_NAME = "property";

        private readonly XmlDocument _document;

        public TaskListService()
        {
            var taskConfigFullName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory,
                "App_Data/AutoTaskSchedule/TaskList.xml");
            if (Directory.Exists(taskConfigFullName))
                throw new FileNotFoundException(taskConfigFullName + "配置文件不存在");

            TASK_CONFIG_FULL_NAME = taskConfigFullName;
            _document = new ConfigXmlDocument();
            _document.Load(TASK_CONFIG_FULL_NAME);
        }

        public string TASK_CONFIG_FULL_NAME { get; private set; }

        public List<Task> FindAll()
        {
            var results = new List<Task>();
            var xmlNodeList = _document.GetElementsByTagName(TASK_TAG_NAME);

            var properties = typeof(Task).GetProperties();

            foreach (XmlNode xmlNode in xmlNodeList)
                try
                {
                    var result = new Task();
                    if (xmlNode.OwnerDocument != null)
                    {
                        #region 获取Task数据

                        var optionNodeList = xmlNode.SelectNodes("options/option");
                        foreach (XmlNode optionNode in optionNodeList)
                        {
                            var optionValue = optionNode.TryGet<string>("value");
                            if (string.IsNullOrEmpty(optionValue)) continue;

                            var optionName = optionNode.TryGet<string>("name");


                            var peropertyInfo =
                                properties.Where(m => m.Name.ToLower() == optionName.ToLower()).FirstOrDefault();
                            if (peropertyInfo == null || peropertyInfo.PropertyType.IsClass) continue;
                            peropertyInfo.SetValue(result, Utils.ChangeType(optionValue, peropertyInfo.PropertyType));
                        }

                        #endregion

                        #region 获取默认参数

                        var propertyNodeList = xmlNode.SelectNodes("properties/property");
                        foreach (XmlNode propertyNode in propertyNodeList)
                        {
                            var name = propertyNode.TryGet<string>("name");
                            var value = propertyNode.TryGet<string>("value");

                            result.TaskProperty.Add(new TaskProperty(name, value));
                        }

                        #endregion
                    }
                    results.Add(result);
                }
                catch
                {
                    // ignored
                }
            return results;
        }

        public Task Find(Guid id)
        {
            return FindAll().FirstOrDefault(t => t.Id == id);
        }

        public void New(Task task)
        {
            var rootNode = _document.SelectSingleNode("/taskList");
            if (rootNode == null) return;

            var newTaskNode = _document.CreateElement("task");
            var optionsNode = _document.CreateElement("options");
            var properties = typeof(Task).GetProperties();
            foreach (var property in properties)
            {
                if (property.PropertyType == task.TaskProperty.GetType())
                    continue;
                var optionNode = _document.CreateElement(TASK_OPTION_TAG_NAME);

                var nameAttribute = _document.CreateAttribute("name");
                nameAttribute.Value = property.Name.ToLower();

                var valueNode = _document.CreateAttribute("value");
                var value = property.GetValue(task);
                if (value == null) continue;
                valueNode.Value = value.ToString();

                optionNode.Attributes.Append(nameAttribute);
                optionNode.Attributes.Append(valueNode);
                optionsNode.AppendChild(optionNode);
            }

            var propertiesNode = _document.CreateElement("properties");
            foreach (var property in task.TaskProperty)
            {
                var propertyNode = _document.CreateElement(TASK_PROPERTY_TAG_NAME);
                var nameAttribute = _document.CreateAttribute("name");
                nameAttribute.Value = property.Name;

                var valueNode = _document.CreateAttribute("value");
                var value = property.Value;
                valueNode.Value = value == null ? string.Empty : value.ToString();

                propertyNode.Attributes.Append(nameAttribute);
                propertyNode.Attributes.Append(valueNode);
                propertiesNode.AppendChild(propertyNode);
            }
            newTaskNode.AppendChild(optionsNode);
            newTaskNode.AppendChild(propertiesNode);
            rootNode.AppendChild(newTaskNode);
            _document.Save(TASK_CONFIG_FULL_NAME);
        }

        /// <summary>
        ///     修改task节点
        /// </summary>
        /// <param name="task"></param>
        public void Modify(Task task)
        {
            Remove(task.Id);
            New(task);
        }

        /// <summary>
        ///     删除task节点
        /// </summary>
        /// <param name="id"></param>
        public void Remove(Guid id)
        {
            try
            {
                var xmlElement = GetTaskElement(id);
                if (xmlElement == null) return;
                xmlElement.RemoveAll();
            }
            catch
            {
                // ignored
            }
        }

        private XmlNode GetTaskElement(Guid id)
        {
            var xpath = string.Format("/taskList/task/options/option[@value=\"{0}\"]", id);
            var xmlElement = _document.SelectSingleNode(xpath);
            if (xmlElement == null) return null;
            if (xmlElement.ParentNode != null) return xmlElement.ParentNode.ParentNode;
            return null;
        }
    }
}